package com.showtao.front.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.showtao.common.enumeration.EErrorCode;
import com.showtao.common.exception.BizServiceException;
import com.showtao.front.domain.Article;
import com.showtao.front.domain.ArticleStatus;
import com.showtao.front.domain.Catalog;
import com.showtao.front.domain.Message;
import com.showtao.front.domain.Tag;
import com.showtao.front.dto.ArticleDto;
import com.showtao.front.dto.CatalogDto;
import com.showtao.front.dto.CatalogSelectionDto;
import com.showtao.front.dto.upstream.ArticleSavingDto;
import com.showtao.front.dto.upstream.CatalogSavingDto;
import com.showtao.front.dto.upstream.MessageSavingDto;
import com.showtao.front.dto.upstream.TagSavingDto;
import com.showtao.front.repository.ArticleRepository;
import com.showtao.front.repository.CatalogRepository;
import com.showtao.front.repository.MessageRepository;
import com.showtao.front.repository.TagRepository;

@Service
public class ContentService {

	@Autowired
	private TagRepository tagRepository;
	@Autowired
	private CatalogRepository catalogRepository;
	@Autowired
	private ArticleRepository articleRepository;
	@Autowired
	private MessageRepository messageRepository;

	@Transactional(readOnly = true)
	public Page<Tag> findTags(Pageable pageable) {
		return tagRepository.findAll(pageable);
	}

	@Transactional(readOnly = true)
	@Cacheable(value = "allTags")
	public List<Tag> findAllTags() {
		return tagRepository.findAll();
	}

	@Transactional
	@CacheEvict(value = "allTags")
	public void deleteTag(Long id) {
		tagRepository.delete(id);
	}

	@Transactional
	@CacheEvict(value = "allTags")
	public void saveTag(TagSavingDto dto) {
		Tag entity = null;
		if (dto.getId() != null) {
			entity = tagRepository.getOne(dto.getId());
			if (entity == null) {
				throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
						"找不到ID=" + dto.getId() + "的Tag实体");
			}
		} else {
			entity = new Tag();
			entity.setCreatedAt(Calendar.getInstance().getTime());
		}
		entity.setName(StringUtils.trim(dto.getName()));
		entity.setAlias(StringUtils.trim(dto.getAlias()));
		entity.setUpdatedAt(Calendar.getInstance().getTime());
		tagRepository.save(entity);
	}

	@Transactional(readOnly = true)
	@Cacheable(value = "allCatalogInFlat")
	public List<CatalogSelectionDto> findAllCatalogInFlat() {
		List<CatalogSelectionDto> result = new ArrayList<CatalogSelectionDto>();
		List<Catalog> cats = catalogRepository.findTops();
		for (Catalog cat : cats) {
			result.add(CatalogSelectionDto.from(cat));
			for (Catalog c : cat.getChildren()) {
				CatalogSelectionDto d = CatalogSelectionDto.from(c);
				d.setLevel(2);
				result.add(d);
				for (Catalog c2 : c.getChildren()) {
					CatalogSelectionDto d2 = CatalogSelectionDto.from(c2);
					d2.setLevel(3);
					result.add(d2);
				}
			}
		}
		return result;
	}

	@Transactional(readOnly = true)
	public Catalog getCatalogByAlias(String alias) {
		try {
			return catalogRepository.getByAliasLeftJoinParent(alias);
		} catch (RuntimeException e) {
			throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
					e.getMessage(), e);
		}
	}

	@Transactional(readOnly = true)
	@Cacheable(value = "subCatalogs", key = "'CATALOG-' + #catalogId")
	public List<Catalog> getSubCatalogs(Long catalogId) {
		return catalogRepository.findByParentId(catalogId);
	}

	@Transactional(readOnly = true)
	@Cacheable(value = "subCatalogs", key = "'CATALOG-' + #alias")
	public List<Catalog> getSubCatalogsByAlias(String alias) {
		try {
			return catalogRepository.findByParentAlias(alias);
		} catch (RuntimeException e) {
			throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
					e.getMessage(), e);
		}
	}

	@Transactional(readOnly = true)
	@Cacheable(value = "navCatalogs")
	public List<Catalog> findNavCatalogs() {
		return catalogRepository.findSimpleTops();
	}

	@Transactional(readOnly = true)
	@Cacheable(value = "articlesInAboutCatalog")
	public List<Article> findArticlesInAboutCatalog() {
		Catalog about = catalogRepository.getByAliasLeftJoinParent("about");
		Page<Article> page = articleRepository.findByCatalog(about, null);
		return page.getContent();
	}

	@Transactional(readOnly = true)
	public Page<CatalogDto> findCatalogs(Pageable pageable) {
		Page<Catalog> page = catalogRepository.findAllLeftJoinParent(pageable);
		List<CatalogDto> list = new ArrayList<CatalogDto>();
		for (Catalog c : page) {
			list.add(CatalogDto.from(c));
		}
		Page<CatalogDto> result = new PageImpl<CatalogDto>(list, pageable,
				page.getTotalElements());
		return result;
	}

	@Transactional
	@Caching(evict = { 
	        @CacheEvict(value = "subCatalogs", key = "'CATALOG-' + #id"), 
	        @CacheEvict(value = "navCatalogs"),
	        @CacheEvict(value = "allCatalogInFlat") 
	        })
	public void deleteCatalog(Long id) {
		catalogRepository.delete(id);
	}

	@Transactional
	@Caching(evict = { 
            @CacheEvict(value = "subCatalogs", key = "'CATALOG-' + #id"), 
            @CacheEvict(value = "navCatalogs"),
            @CacheEvict(value = "allCatalogInFlat") 
            })
	public void saveCatalog(CatalogSavingDto dto) {
		Catalog entity = null;
		Catalog parent = null;
		if (dto.getId() != null) {
			entity = catalogRepository.getOne(dto.getId());
			if (entity == null) {
				throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
						"找不到ID=" + dto.getId() + "的Catalog实体");
			}
		} else {
			entity = new Catalog();
			entity.setCreatedAt(Calendar.getInstance().getTime());
		}
		entity.setName(StringUtils.trim(dto.getName()));
		entity.setAlias(StringUtils.trim(dto.getAlias()));
		entity.setUpdatedAt(Calendar.getInstance().getTime());
		entity = catalogRepository.save(entity);

		// update parents
		if (dto.getParentId() != null) {
			parent = catalogRepository.getOne(dto.getParentId());
			if (parent == null) {
				throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
						"找不到ID=" + dto.getId() + "的Catalog.parent实体");
			}
			entity.setParent(parent);
		}
		catalogRepository.save(entity);
	}

	@Transactional(readOnly = true)
	@Cacheable(value = "articles", key = "'ARTICLE-' + #id")
	public Article getArticle(Long id) {
		return articleRepository.getByIdLeftJoinCatalogAndTags(id);
	}

	@Transactional(readOnly = true)
	public Article getTheFirstArticleByTagAlias(String alias) {
		List<Article> articles = articleRepository.getByTagAlias(alias);
		return articles != null && articles.size() != 0 ? articles.get(0)
				: null;
	}

	@Transactional(readOnly = true)
	public Page<ArticleDto> findArticles(Pageable pageable) {
		Page<Article> page = articleRepository
				.findAllLeftJoinCatalogAndTags(pageable);
		List<ArticleDto> list = new ArrayList<ArticleDto>();
		for (Article a : page) {
			list.add(ArticleDto.from(a));
		}
		Page<ArticleDto> result = new PageImpl<ArticleDto>(list, pageable,
				page.getTotalElements());
		return result;
	}

	@Transactional(readOnly = true)
	public Page<ArticleDto> findArticlesByCatalogId(Long catalogId,
			Pageable pageable) {
		if ( catalogId ==  null) {
			throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
					"参数catalogId不能为空");
		}
		Catalog catalog = catalogRepository.getOne(catalogId);
		if (catalog == null) {
			throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
					"找不到ID=" + catalogId + "的Catalog对象");
		}
		Page<Article> page = articleRepository.findByCatalogLeftJoinTags(
				catalog, ArticleStatus.PUBLISHED, pageable);
		List<ArticleDto> list = new ArrayList<ArticleDto>();
		for (Article a : page) {
			list.add(ArticleDto.from(a));
		}
		Page<ArticleDto> result = new PageImpl<ArticleDto>(list, pageable,
				page.getTotalElements());
		return result;
	}

	public long countArticlesByCatalogAndStatus(Catalog c, ArticleStatus status) {
		return articleRepository.countByCatalogAndStatus(c, status);
	}

	public Article getTheFirstArticleByCatalogAndStatus(Catalog c,
			ArticleStatus status) {
		return articleRepository.getByCatalogAndStatus(c, status);
	}

	@Transactional
	@CacheEvict(value = "articles", key = "'ARTICLE-' + #id")
	public void deleteArticle(Long id) {
		articleRepository.delete(id);
	}

	@Transactional
	@CacheEvict(value = "articles", key = "'ARTICLE-' + #dto.id")
	public void saveArticle(ArticleSavingDto dto) {
		Article entity = null;
		Catalog catalog = null;
		if (dto.getId() != null) {
			entity = articleRepository.getOne(dto.getId());
			if (entity == null) {
				throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
						"找不到ID=" + dto.getId() + "的Article实体");
			}
		} else {
			entity = new Article();
			entity.setCreatedAt(Calendar.getInstance().getTime());
		}
		entity.setTitle(StringUtils.trim(dto.getTitle()));
		entity.setContent(StringUtils.trim(dto.getContent()));
		entity.setStatus(dto.getStatus());
		entity.setUpdatedAt(Calendar.getInstance().getTime());

		// update catalog
		if ( dto.getCatalogId() != null) {
			catalog = catalogRepository.getOne(dto.getCatalogId());
			if (catalog == null) {
				throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
						"找不到ID=" + dto.getId() + "的Article.catalog实体");
			}
			entity.setCatalog(catalog);
		}

		// update the tag associations
		if (entity.getTags() == null) {
			entity.setTags(new HashSet<Tag>());
		}
		entity.getTags().clear();
		if (dto.getTagIds() != null) {
			for (Long id : dto.getTagIds()) {
				Tag tag = tagRepository.getOne(id);
				if (tag != null) {
					entity.getTags().add(tag);
				}
			}
		}
		articleRepository.save(entity);
	}
	
	@Transactional(readOnly = true)
	public Page<Message> findMessages(Pageable pageable) {
		return messageRepository.findAll(pageable);
	}
	
	@Transactional
	public void deleteMessage(Long id) {
		messageRepository.delete(id);
	}
	
	@Transactional
	public void saveMessage(MessageSavingDto dto) {
		Message entity = null;
		if (dto.getId() != null) {
			entity = messageRepository.getOne(dto.getId());
			if (entity == null) {
				throw new BizServiceException(EErrorCode.COMM_INTERNAL_ERROR,
						"找不到ID=" + dto.getId() + "的Message实体");
			}
		} else {
			entity = new Message();
			entity.setCreatedAt(Calendar.getInstance().getTime());
		}
		entity.setTitle(StringUtils.trim(dto.getTitle()));
		entity.setContent(StringUtils.trim(dto.getContent()));
		if(!StringUtils.isEmpty(dto.getContact())){
			if(dto.getContact().indexOf("@") != -1){
				entity.setEmail(dto.getContact());
			}else{
				entity.setMobile(dto.getContact());
			}
		}
		entity.setUpdatedAt(Calendar.getInstance().getTime());
		messageRepository.save(entity);
	}
}
